package SystemB;

/******************************************************************************************************************
* File:SecurityMonitor.java
* Course: 17655
* Project: Assignment A3
* Copyright: Copyright (c) 2013 Carnegie Mellon University
* Versions:
*	1.0 March 2013 - subbu
*
* 
******************************************************************************************************************/
import EventPackage.*;
import InstrumentationPackage.*;
import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.KeyEvent;

class SecurityMonitor extends Thread
{
	private EventManagerInterface em = null;// Interface object to the event manager
	private String EvtMgrIP = null;			// Event Manager IP address
	boolean AlarmOn = false;                        // current state of Fire Alarm
        boolean SprinklerOn = false;                    // current state of Sprinkler
        boolean Registered = true;				// Signifies that this class is registered with an event manager.
	MessageWindow mw = null;				// This is the message window
	boolean ON = true;						//indicates if system is armed or disarmed
	Indicator si;
	String AlertType="";
        private int mode = 0; 
        private int counter = 0;             	//  to count 15 seconds to wait to turn on sprinklers

	public SecurityMonitor()
	{
		// event manager is on the local system

		try
		{
			// Here we create an event manager interface object. This assumes
			// that the event manager is on the local machine

			em = new EventManagerInterface();

		}

		catch (Exception e)
		{
			System.out.println("SecurityMonitor::Error instantiating event manager interface: " + e);
			Registered = false;

		} // catch

	} //Constructor

	public SecurityMonitor( String EvmIpAddress )
	{
		// event manager is not on the local system

		EvtMgrIP = EvmIpAddress;

		try
		{
			// Here we create an event manager interface object. This assumes
			// that the event manager is NOT on the local machine

			em = new EventManagerInterface( EvtMgrIP );
		}

		catch (Exception e)
		{
			System.out.println("SecurityMonitor::Error instantiating event manager interface: " + e);
			Registered = false;

		} // catch

	} // Constructor

	public void run()
	{
		Event Evt = null;				// Event object
		EventQueue eq = null;			// Message Queue
		int EvtId = 0;					// User specified event ID
		int	Delay = 1000;				// The loop delay (1 second)
		boolean Done = false;			// Loop termination flag

		if (em != null)
		{
			// Now we create the SecurtyMonitor status and message panel
		

			mw = new MessageWindow("Security Monitoring Console", 0.5f, 0);
			si = new Indicator ("ARMED", mw.GetX()+ mw.Width(), 0); //indicates status of security system
			
			mw.WriteMessage( "Registered with the event manager." );

	    	try
	    	{
				mw.WriteMessage("   Participant id: " + em.GetMyId() );
				mw.WriteMessage("   Registration Time: " + em.GetRegistrationTime() );

			} // try

	    	catch (Exception e)
			{
				System.out.println("Error:: " + e);

			} // catch

			/********************************************************************
			** Here we start the main simulation loop
			*********************************************************************/

			while ( !Done )
			{
                            
                            //set the right mode                            
                                //sprinkler is on
                                if (SprinklerOn && this.getMode() != 2)
                                {
                                    //when the sprinkler is on, set mode to turn it off
                                    this.setMode(2);
                                } //if
                                
                                //sprinkler is off and fire alarm is on
                               if (!SprinklerOn && AlarmOn && this.getMode() != 1)
                               {
                                    //when the sprinkler is off, and fire alarm on set mode to 1
                                    this.setMode(1);
                               } //if
                               
                                //sprinkler is off and fire alarm is ff
                               if (!SprinklerOn && !AlarmOn && this.getMode() != 0)
                               {
                                    //when the sprinkler is off, and fire alarm is off set mode to normal security console
                                    this.setMode(0);
                               } //if
                               
				// Here we get our event queue from the event manager

                                try
				{
					eq = em.GetEventQueue();

				} // try

				catch( Exception e )
				{
					mw.WriteMessage("Error getting event queue::" + e );

				} // catch

				// If there are messages in the queue, we read through them.
				// We are looking for EventIDs = 6.
				//Note that we get all the messages at once... there is a 1
				// second delay between samples,.. so the assumption is that there should
				// only be a message at most. If there are more, it is the last message
				// that will effect the state of the security sytem

				String AlertString = new String();
				int qlen = eq.GetSize();

				for ( int i = 0; i < qlen; i++ )
				{
					Evt = eq.GetEvent();

					if ( (Evt.GetEventId() == 6)) // Security alert reading
					{
						try
						{
							AlertType= Evt.GetMessage();
							//set indicator color based on alert type received
							switch(AlertType)
							{
							case "WB": 
									if (ON) si.SetLampColorAndMessage("WINDW BRK!",1);
									AlertString = "Window Break Detected!"; //this string will be displayed in the console
									break;
							case "DB": 	
									if (ON) si.SetLampColorAndMessage("DOOR BRK!",2);
									AlertString = "Door Break Detected!"; //this string will be displayed in the console
									break;
							case "MD": 
									if (ON) si.SetLampColorAndMessage("MOV DTCTD!",1);
									AlertString = "Movement Detected!"; //this string will be displayed in the console
									break;
							case "RST": 
									if (ON) si.SetLampColorAndMessage("ARMED!",0);
									AlertString = "All Alerts cleared.System Armed"; //this string will be displayed in the console
									break;
							case "ON": 
									if (ON) si.SetLampColorAndMessage("ARMED!",0);
									AlertString = "Arming system for security events"; //this string will be displayed in the console
                                                                        break;
                                                        case "OFF": 
									si.SetLampColorAndMessage("NOT ARMED!",2);
									mw.WriteMessage( "Disarming system...security events are not reported" );
									break;
                                         
                                                        default: break;
							}
                                                       
                                                        //only print messages if the system is armed
                                                        if (ON) mw.WriteMessage(AlertString);

						} // try

						catch( Exception e )
						{
							mw.WriteMessage("Error reading Security alert: " + e);

						} // catch
					
					} // if
                                        
                                        if ( Evt.GetEventId() == -10 ) // Fire Alarm event
					{
						try
						{
                                                    
                                                    switch (Evt.GetMessage() )
                                                    {
                                                        case "F1" : 
                                                             AlarmOn = true;
                                                             si.SetLampColorAndMessage("ALRM ON", 3);
                                                             mw.WriteMessage( "FIRE ALARM!" );
                                                             break;
                                                            
                                                        
                                                        case "F0" :
                                                             AlarmOn = false;
                                                             si.SetLampColorAndMessage("ALRM OFF", 1);
                                                             mw.WriteMessage( "Fire Alarm deactivated...");                               
                                                             break;
                                        
                                                    } //switch
            
						} // try

						catch( Exception e )
						{
							mw.WriteMessage("Error reading fire alarm: " + e);

						} // catch

					} // if

					if ( Evt.GetEventId() == -11 ) // sprinkler reading
					{
						try
						{
				
						    switch (Evt.GetMessage() )
                                                    {
                                                        case "S1" : 
                                                             SprinklerOn = true;
                                                             mw.WriteMessage( "Sprinklers Activated!" );
                                                             break;
                                                        
                                                        case "S0" :
                                                             SprinklerOn = false;
                                                             mw.WriteMessage( "Sprinklers Deactivated..." );
                                                             break;
                                        
                                                    } //switch

						} // try

						catch( Exception e )
						{
							mw.WriteMessage("Error reading sprinkler: " + e);

						} // catch

					} // if
					
				// If the event ID == 99 then this is a signal that the simulation
				// is to end. At this point, the loop termination flag is set to
				// true and this process unregisters from the event manager.

				if ( Evt.GetEventId() == 99 )
				{
					Done = true;

					try
					{
						em.UnRegister();

			    	} // try

			    	catch (Exception e)
			    	{
						mw.WriteMessage("Error unregistering: " + e);

			    	} // catch

                                    mw.WriteMessage( "\n\nSimulation Stopped. \n");

					// Get rid of the indicators. The message panel is left for the
					// user to exit so they can see the last message posted.

					si.dispose();

                                    } // if

                                } //for	                            	
					
                                //if the fire alarm is on and the sprinkler is off. wait 15s and turn it on
                                if (AlarmOn && !SprinklerOn)
                                {
                                    if (counter >= 15000/Delay)
                                    {
                                        this.Sprinkler(true);
                                        counter = 0;                                      
                                    } //if
                                    else
                                    {
                                        counter++;
                                        mw.WriteMessage("Sprinkler active in " + (15000/Delay-counter) +"s");
                                    } //else
                                } //if
                               
                                                   
				// This delay slows down the sample rate to Delay milliseconds
	
					try
					{
						Thread.sleep( Delay );
	
					} // try
	
					catch( Exception e )
					{
						System.out.println( "Sleep error:: " + e );
	
					} // catch

			} // while

		} else {

			System.out.println("Unable to register with the event manager.\n\n" );

		} // if

	} // main

	/***************************************************************************
	* CONCRETE METHOD:: IsRegistered
	* Purpose: This method returns the registered status
	*
	* Arguments: none
	*
	* Returns: boolean true if registered, false if not registered
	*
	* Exceptions: None
	*
	***************************************************************************/

	public boolean IsRegistered()
	{
		return( Registered );

	} 

	/***************************************************************************
	* CONCRETE METHOD:: Halt
	* Purpose: This method posts an event that stops the environmental control
	*		   system.
	*
	* Arguments: none
	*
	* Returns: none
	*
	* Exceptions: Posting to event manager exception
	*
	***************************************************************************/

	public void Halt()
	{
		mw.WriteMessage( "***HALT MESSAGE RECEIVED - SHUTTING DOWN SYSTEM***" );

		// Here we create the stop event.

		Event evt;

		evt = new Event( (int) 99, "XXX" );

		// Here we send the event to the event manager.

		try
		{
			em.SendEvent( evt );

		} // try

		catch (Exception e)
		{
			System.out.println("Error sending halt message:: " + e);

		} // catch

	} // Halt
	
        public void ArmSystem()
	{
		Event evt;
		evt = new Event( (int) 6, "ON" );
		try
		{
			em.SendEvent( evt );
                        ON = true;                   
		} // try

		catch (Exception e)
		{
			System.out.println("Error sending ON message:: " + e);

		} // catch
				
	} //Arm System
	
        public void DisarmSystem() //method to disarm the security system
	{
		Event evt;
		evt = new Event( (int) 6, "OFF" );
		try
		{
			em.SendEvent( evt );
                        ON = false;                    
		} // try

		catch (Exception e)
		{
			System.out.println("Error sending OFF message:: " + e);

		} // catch
	} //Disarm System

        /***************************************************************************
	* CONCRETE METHOD:: Sprinkler
	* Purpose: This method posts events that will signal the sprinkler
	*		   on/off 
	*
	* Arguments: boolean ON(true)/OFF(false) - indicates whether to turn the
	*			 sprinkler on or off.
	*
	* Returns: none
	*
	* Exceptions: Posting to event manager exception
	*
	***************************************************************************/

	public void Sprinkler( boolean ON )
	{
                  
                counter = 0; // reset the 15s count if there is a sprinkler event
                
                // Here we create the event.
		Event evt = null;

		if ( ON )
		{
			//only create event if sprinkler is not on
                        if (!SprinklerOn)
                        {
                            evt = new Event( (int) 11, "S1" );
                            mw.WriteMessage( "Sent Sprinkler ON event" );
                            SprinklerOn = true;
                        }

		} else {
                        //only create event if sprinkler is on
                        if (SprinklerOn)
                        {
                            evt = new Event( (int) 11, "S0" );
                            mw.WriteMessage( "Sent Sprinkler OFF event" );
                            SprinklerOn = false;
                        }
                            

		} // if

		// Here we send the event to the event manager.

                if (evt != null)
                {
                  
                    try
                    {
			em.SendEvent( evt );

                    } // try

                    catch (Exception e)
                    {
			System.out.println("Error sending sprinkler control message:: " + e);

                    } // catch
                } // if

	} // Sprinkler

	/***************************************************************************
	* CONCRETE METHOD:: FireAlarm
	* Purpose: This method posts events that will signal the Fire Alarm
	*		   controller to turn on/off
	*
	* Arguments: boolean ON(true)/OFF(false) - indicates whether to turn the
	*			 fire alarm n or off.
	*
	* Returns: none
	*
	* Exceptions: Posting to event manager exception
	*
	***************************************************************************/

	public void FireAlarm( boolean ON )
	{
		
                counter = 0; // reset the 15s count if there is a fire alarm event
		
                // Here we create the event.
                Event evt = null;		
                if ( ON )
		{
			// only send event if alarm is off
                        if (!AlarmOn)
                        {
                            evt = new Event( (int) 10, "true" );
                            mw.WriteMessage( "Sent Fire Alarm ON event" );
                            AlarmOn = true;
                        }

		} else {
                    
                        // only send event if alarm is on
                        if (AlarmOn)
                        {
                            evt = new Event( (int) 10, "false" );
                            mw.WriteMessage( "Sent Fire Alarm OFF event" );
                            AlarmOn = false;
                        }
			
		} // if
        
		// Here we send the event to the event manager.
                
                if (evt != null)
                {
                    try
                    {
			em.SendEvent( evt );

                    } // try

                    catch (Exception e)
                    {
			System.out.println("Error sending fire alarm control message:: " + e);

                    } // catch
                } // if

	} // Fire Alarm

        
    /**
     * @return the mode
     */
    public int getMode() {
        return mode;
    } // get mode

    
    /**
     * @param mode the mode to set
     */
    public void setMode(int mode) {
        
        Robot robot = null;  // Used to issue a keyboard command to force the refresh of the console mode
        
        try {
            robot = new Robot();
        } catch (AWTException ex) {
            System.out.println("Error sending robot keyboard event:: " + ex);
            
        }
        
        this.mode = mode;
        robot.keyPress(KeyEvent.VK_ENTER);
        
    } //set mode

    public void PostSmoke( boolean smokeState )
	{
		// Here we create the event.

		Event evt = new Event( (int) 10, String.valueOf(smokeState) );

		// Here we send the event to the event manager.

		try
		{
			em.SendEvent( evt );
			//mw.WriteMessage( "Sent Smoke Event" );

		} // try

		catch (Exception e)
		{
			System.out.println( "Error Posting Smoke:: " + e );

		} // catch

	} // PostSmoke
} // SecurityMonitor